package rwt.server;

import java.util.*;

import rwt.server.core.BaseMessage;
import rwt.server.railroad.SwitchStatus;

/**
 * Messages that pass between this web server and web clients. These messages are converted into JSON format
 * and sent over a WebSocket connection.
 */
public class WebMessages
{
	// System status
	public static final int SYSTEM_STATUS_STOPPED = 0;
	public static final int SYSTEM_STATUS_RUNNING = 1;
	public static final int SYSTEM_STATUS_STARTING = 2;
	public static final int SYSTEM_STATUS_STOPPING = 3;
	
	// Train availability status
	public static final int TRAIN_UNINITIALIZED = 0;
	public static final int TRAIN_TAKEN_BASIC = 1;
	public static final int TRAIN_TAKEN_DIRECT = 2;
	public static final int TRAIN_AVAILABLE = 3;
	
	private final static int SWITCH_CLOSED = 0;
	private final static int SWITCH_THROWN = 1;
	private final static int SWITCH_BEGIN_CLOSED = 2;
	private final static int SWITCH_BEGIN_THROWN = 3;
	private final static int SWITCH_UNKNOWN = 4;
	
	public static class WelcomeMessage extends BaseMessage
	{
		public String userName;
		
		public WelcomeMessage(String userName)
		{
			this.userName = userName;
		}
	}
	
	public static class ChangeSystemStatus extends BaseMessage
	{
		public int systemStatus;
	}
	
	public static class DoInitializeTrain extends BaseMessage
	{
		public int trainId;
		public int headSensor;
		public int tailSensor;
	}

	public static class ChangePowerStatus extends BaseMessage
	{
		public int onOffState;
	}
	
	public static class SetTrainSpeed extends BaseMessage
	{
		public int trainId;
		public int speed;
	}
	
	public static class SetTrainDirection extends BaseMessage
	{
		public int trainId;
		public int direction;
	}
	
	public static class SetTrainLight extends BaseMessage
	{
		public int trainId;
		public int light;
	}

	public static class SetTrainHorn extends BaseMessage
	{
		public int trainId;
		public int horn;
	}

	public static class SetTrainBell extends BaseMessage
	{
		public int trainId;
		public int bell;
	}

	public static class SetTrainMute extends BaseMessage
	{
		public int trainId;
		public int mute;
	}

	public static class SetTrainNextSwitch extends BaseMessage
	{
		public int trainId;
		public int closeOrThrow; // Close = 0, Throw = 1
	}
	
	public static class SetSwitch extends BaseMessage
	{
		public int switchId;
	}
	
	public static class PutSystemStatus extends BaseMessage
	{
		public int systemStatus;
		
		public PutSystemStatus(int systemStatus)
		{
			this.systemStatus = systemStatus;
		}
	}

	public static class PutInitializeTrain extends BaseMessage
	{
		public int trainId;
		public boolean succeeded;
		public String reason;
		
		// Successful initialization
		public PutInitializeTrain(int trainId)
		{
			this.succeeded = true;
			this.trainId = trainId;
		}
		
		// Unsuccessful initialization
		public PutInitializeTrain(int trainId, String reason)
		{
			this.succeeded = false;
			this.trainId = trainId;
			this.reason = reason;
		}
	}
	
	public static class PutAvailableTrains extends BaseMessage
	{
		public Map<Integer, Integer> trainStates;
		public Map<Integer, String> trainOperators;
		
		public PutAvailableTrains(Map<Integer, Integer> trainStates, Map<Integer, String> trainOperators)
		{
			this.trainStates = trainStates;
			this.trainOperators = trainOperators;
		}
	}
	
	public static class PutTrainState extends BaseMessage
	{
		public int trainId;
		public int state;
		
		public PutTrainState(int trainId, int state)
		{
			this.trainId = trainId;
			this.state = state;
		}
	}
	
	public static class PutTrainInfo extends BaseMessage
	{
		public int trainId;
		public int speed;
		public int direction;
		public int light;
		public int bell;
		public int horn;
		public int mute;
	}
	
	
	public static class OpenSwitchesRequest extends BaseMessage
	{
		public boolean isEmergency;
		public int switchType;
	}
	
	public static class OpenSwitchesResponse extends BaseMessage
	{
		public boolean granted;
		public int switchType;
		
		public OpenSwitchesResponse(boolean granted, int switchType)
		{
			this.granted = granted;
			this.switchType = switchType;
		}
	}
	
	public static class CloseSwitchRequest extends BaseMessage {}
	
	public static class CloseSwitches extends BaseMessage
	{
		public int garb = 0;
	}
	
	public static class PutSwitchState extends BaseMessage
	{
		public int switchId;
		public int state;
		
		public PutSwitchState(int switchId, int state)
		{
			this.switchId = switchId;
			this.state = state;
		}
	}
	
	public static class GetSwitches extends BaseMessage {}
	
	public static class PutSwitches extends BaseMessage
	{
		@SuppressWarnings("unused")
		private class SwitchState
		{
			public int switchId;
			public int state;
		}
		public SwitchState[] switchStates;
		
		public PutSwitches(Map<Integer, SwitchStatus> switches)
		{
			switchStates = new SwitchState[switches.size()];
			int index = 0;
			for (int switchId : switches.keySet())
			{
				switchStates[index] = new SwitchState();
				switchStates[index].switchId = switchId;
				SwitchStatus state = switches.get(switchId);
				switch (state)
				{
				case BeginThrown:
					switchStates[index].state = SWITCH_BEGIN_THROWN;
					break;
				case BeginClosed:
					switchStates[index].state = SWITCH_BEGIN_CLOSED;
					break;
				case Closed:
					switchStates[index].state = SWITCH_CLOSED;
					break;
				case Thrown:
					switchStates[index].state = SWITCH_THROWN;
					break;
				case Unknown:
				default:
					switchStates[index].state = SWITCH_UNKNOWN;
					break;
				}
				index++;
			}
		}
	}
	
	public static class OpenThrottleRequest extends BaseMessage
	{
		public int trainId;
		public boolean direct;
	}
	
	public static class OpenThrottleResponse extends BaseMessage
	{
		public int trainId;
		public int virtualAddress;
		public boolean granted;
		public boolean emergency;
		
		public OpenThrottleResponse(int trainId, int virtualAddress, boolean granted, boolean emergency)
		{
			this.trainId = trainId;
			this.virtualAddress = virtualAddress;
			this.granted = granted;
			this.emergency = emergency;
		}
	}
	
	public static class CloseThrottle extends BaseMessage
	{
		public int trainId;
	}
}
